#include "include/core/SkFontTypes.h"

#include <codecvt>
#include <locale>
#include <string>
#include "stdint.h"

std::string UTF16ToUTF8(const char16_t* text, size_t byteLength) {
    if (!text || byteLength % 2 != 0) return {};
    
    size_t length = byteLength / sizeof(char16_t);
    std::u16string utf16Str(text, text + length);

#if __cplusplus >= 201703L
    std::string utf8Str;
    for (char16_t ch : utf16Str) {
        if (ch <= 0x7F) {
            utf8Str.push_back(static_cast<char>(ch));
        } else if (ch <= 0x7FF) {
            utf8Str.push_back(0xC0 | (ch >> 6));
            utf8Str.push_back(0x80 | (ch & 0x3F));
        } else {
            utf8Str.push_back(0xE0 | (ch >> 12));
            utf8Str.push_back(0x80 | ((ch >> 6) & 0x3F));
            utf8Str.push_back(0x80 | (ch & 0x3F));
        }
    }
    return utf8Str;
#else
    std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
    return converter.to_bytes(utf16Str);
#endif
}

std::string UTF32ToUTF8(const char32_t* text, size_t byteLength) {
    if (!text || byteLength % 4 != 0) return {};
    
    size_t length = byteLength / sizeof(char32_t);
    std::u32string utf32Str(text, text + length);

#if __cplusplus >= 201703L
    std::string utf8Str;
    for (char32_t ch : utf32Str) {
        if (ch <= 0x7F) {
            utf8Str.push_back(static_cast<char>(ch));
        } else if (ch <= 0x7FF) {
            utf8Str.push_back(0xC0 | (ch >> 6));
            utf8Str.push_back(0x80 | (ch & 0x3F));
        } else if (ch <= 0xFFFF) {
            utf8Str.push_back(0xE0 | (ch >> 12));
            utf8Str.push_back(0x80 | ((ch >> 6) & 0x3F));
            utf8Str.push_back(0x80 | (ch & 0x3F));
        } else {
            utf8Str.push_back(0xF0 | (ch >> 18));
            utf8Str.push_back(0x80 | ((ch >> 12) & 0x3F));
            utf8Str.push_back(0x80 | ((ch >> 6) & 0x3F));
            utf8Str.push_back(0x80 | (ch & 0x3F));
        }
    }
    return utf8Str;
#else
    std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> converter;
    return converter.to_bytes(utf32Str);
#endif
}

std::string convertToUTF8(const void* text, size_t byteLength, SkTextEncoding encoding) {
    if (!text || byteLength == 0) {
        return {};
    }

    switch (encoding) {
        case SkTextEncoding::kUTF8:
            return std::string(static_cast<const char*>(text), byteLength);
        case SkTextEncoding::kUTF16:
            return UTF16ToUTF8(static_cast<const char16_t*>(text), byteLength);
        case SkTextEncoding::kUTF32:
            return UTF32ToUTF8(static_cast<const char32_t*>(text), byteLength);
        case SkTextEncoding::kGlyphID:
            return {};
        default:
            return {};
    }
}
